home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1993, 1994 Marc Parmet.
- * This file is part of the Macintosh port of GNU Emacs.
- *
- * GNU Emacs is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
- #include <MacHeaders>
- #include "sys/dir.h"
- #include "stdio.h"
- #include "getopt.h"
- #include "regex.h"
- #include "vfork.h"
-
- static char debug = 0;
- static char *progname;
-
- enum {
- noneFoundErr = 3
- };
-
- static char upcase[0400] =
- { 000, 001, 002, 003, 004, 005, 006, 007,
- 010, 011, 012, 013, 014, 015, 016, 017,
- 020, 021, 022, 023, 024, 025, 026, 027,
- 030, 031, 032, 033, 034, 035, 036, 037,
- 040, 041, 042, 043, 044, 045, 046, 047,
- 050, 051, 052, 053, 054, 055, 056, 057,
- 060, 061, 062, 063, 064, 065, 066, 067,
- 070, 071, 072, 073, 074, 075, 076, 077,
- 0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
- 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
- 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
- 0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137,
- 0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
- 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
- 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
- 0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177,
- 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
- 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
- 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
- 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
- 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
- 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
- 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
- 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
- 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
- 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
- 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
- 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
- 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
- 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
- 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
- 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
- };
-
- struct re_pattern_buffer searchbuf;
-
- static void
- init_searchbuf(void)
- {
- #define BYTEWIDTH 8
- char fastmap[(1 << BYTEWIDTH)];
-
- searchbuf.allocated = 40;
- searchbuf.buffer = NewPtr(searchbuf.allocated);
- searchbuf.fastmap = fastmap;
- searchbuf.translate = upcase;
- }
-
- static int
- get_file_list1(char *dirname,int *nfiles,char ****file_list)
- {
- int i,err;
- char *s;
- DIR *dir;
- struct direct *f;
-
- *file_list = 0L;
- *nfiles = 0;
-
- dir = opendir(dirname);
- if (dir == 0L) return memFullErr;
- *file_list = NewHandle(0L);
- while ((f = readdir(dir)) != 0L) {
- SetHandleSize(*file_list,(*nfiles+1) * sizeof(char *));
- err = MemError(); if (err) return err;
- s = NewPtr(strlen(f->d_name) + 1);
- err = MemError(); if (err) return err;
- strcpy(s,f->d_name);
- (**file_list)[*nfiles] = s;
- ++*nfiles;
- }
- closedir(dir);
- return noErr;
- }
-
- static char
- lastchar(char *s)
- {
- int len = strlen(s);
- if (len == 0)
- return '\0';
- else
- return s[len-1];
- }
-
- static int
- get_file_list(char *cwd,char *pathname,int *nfiles,char ****file_list)
- {
- int err;
-
- if (pathname == 0L) {
- if (cwd == 0L) {
- fprintf(stderr,"%s: Cannot expand file names without "
- "current working directory.\n",progname);
- return dirNFErr;
- }
- else
- return get_file_list1(cwd,nfiles,file_list);
- }
- else if (pathname[0] == '/' || (pathname[0] == '~' && pathname[1] != '\0')) {
- return get_file_list1(pathname,nfiles,file_list);
- }
- else {
- int cwd_len,pathname_len;
- char *complete_pathname;
-
- if (cwd == 0L) {
- fprintf(stderr,"%s: Cannot expand file names without "
- "current working directory.\n",progname);
- return 0L;
- }
-
- cwd_len = strlen(cwd);
- pathname_len = strlen(pathname);
- complete_pathname = NewPtr(cwd_len + pathname_len + 2);
- err = MemError(); if (err) return err;
- strcpy(complete_pathname,cwd);
- if (lastchar(cwd) != '/') strcat(complete_pathname,"/");
- strcat(complete_pathname,pathname);
- err = get_file_list1(complete_pathname,nfiles,file_list);
- DisposPtr(complete_pathname);
- return err;
- }
- }
-
- void
- dispose_file_list(char ***file_list,int nfiles)
- {
- int i;
-
- for (i = 0; i<nfiles; ++i)
- DisposPtr((*file_list)[i]);
- DisposHandle(file_list);
- }
-
- static void
- convert_to_unix_pattern(char *in,char **out)
- {
- int i;
-
- *out = NewPtr(strlen(in)*2+3);
- i = 0;
- (*out)[i++] = '^';
- while (1) {
- if (*in == '\0') {
- (*out)[i++] = '$';
- (*out)[i++] = '\0';
- return;
- }
- else if (*in == '*') {
- (*out)[i++] = '.';
- (*out)[i++] = '*';
- }
- else if (*in == '.') {
- (*out)[i++] = '\\';
- (*out)[i++] = '.';
- }
- else
- (*out)[i++] = *in;
-
- ++in;
- }
- }
-
- static int
- find_matches(char ***file_list,int nfiles,char *s,char ***matches,int *nmatches)
- {
- char *t;
- int i,k,len,err;
-
- *nmatches = 0;
- SetHandleSize(matches,0);
-
- convert_to_unix_pattern(s,&t);
- re_compile_pattern(t,strlen(t),&searchbuf);
- DisposPtr(t);
- for (i = 0; i<nfiles; ++i) {
- len = strlen((*file_list)[i]);
- k = re_match(&searchbuf,(*file_list)[i],len,0,0);
- if (k>=0) {
- SetHandleSize(matches,(*nmatches+1) * sizeof(char *));
- err = MemError(); if (err) return err;
- t = NewPtr(strlen((*file_list)[i]) + 1);
- err = MemError(); if (err) return err;
- strcpy(t,(*file_list)[i]);
- (*matches)[*nmatches] = t;
- ++*nmatches;
- }
- }
-
- return noErr;
- }
-
- static void
- separate_pathname_from_filename(char **pathname,char **filename)
- {
- int i;
-
- // Need to separate pathname from filename
- i = strlen(*filename)-1;
- *pathname = 0L;
- while (1) {
- if (i < 0) break;
- if ((*filename)[i] == '/') {
- *pathname = NewPtr(i+2);
- memcpy(*pathname,*filename,i+1);
- (*pathname)[i+1] = '\0';
- *filename = *filename+i+1;
- if (debug) printf("pathname is >%s<, filename is >%s<\n",*pathname,*filename);
- break;
- }
- --i;
- }
- }
-
- static void
- do_one_command(char *cmd)
- {
- int argstart,nmatches,cwd_err;
- int i,j,len,arglen,new_argc1,new_argc2,nfiles,status;
- char cwd[MAXNAMLEN+1];
- int pid;
- char *p,*t,*pathname,*filename,*newprogname;
- char ***matches,***file_list,***new_argv1,***new_argv2;
- short err;
-
- new_argv1 = new_argv2 = 0;
-
- cwd_err = (getwd(cwd) == 0L);
-
- if (debug) printf("sh: Separating arguments...\n");
-
- // args are the words of argv[k]
- i = new_argc1 = 0;
- len = strlen(cmd);
- new_argv1 = NewHandle(0);
- err = MemError(); if (err) goto error;
- while (1) {
- if (i == len) break;
- while (i<len && cmd[i] == ' ')
- ++i;
- if (i == len) break;
- argstart = i;
- while (i<len && cmd[i] != ' ')
- ++i;
- ++new_argc1;
- arglen = i - argstart;
- SetHandleSize(new_argv1,new_argc1 * sizeof(char *));
- err = MemError(); if (err) goto error;
- t = NewPtr(arglen+1);
- err = MemError(); if (err) goto error;
- (*new_argv1)[new_argc1-1] = t;
- memcpy((*new_argv1)[new_argc1-1],cmd+argstart,arglen);
- (*new_argv1)[new_argc1-1][arglen] = '\0';
- }
-
- if (debug) {
- printf("Before expansion, there are %d arguments:\n",new_argc1);
- for (i = 0; i<new_argc1; ++i)
- printf(">%s<\n",(*new_argv1)[i]);
- }
-
- // Remove a first argument 'exec'
- if (!strcmp((*new_argv1)[0],"exec")) {
- for (i = 0; i<new_argc1-1; ++i)
- (*new_argv1)[i] = (*new_argv1)[i+1];
- --new_argc1;
- }
-
- // Need to remove first argument 'env'
-
- new_argc2 = 0;
- new_argv2 = NewHandle(0L);
- err = MemError(); if (err) goto error;
-
- // Need to expand arguments with wildcards relative to cwd.
- for (i = 0; i<new_argc1; ++i) {
- filename = (*new_argv1)[i];
- separate_pathname_from_filename(&pathname,&filename);
-
- if (has_star(filename)) {
- err = get_file_list(cwd_err ? 0L : cwd,pathname,&nfiles,&file_list);
- if (err) continue;
-
- matches = NewHandle(0L);
- if (MemError()) goto error;
- err = find_matches(file_list,nfiles,filename,matches,&nmatches);
- if (err) goto error;
- if (nmatches == 0) { err = noneFoundErr; goto error; }
-
- SetHandleSize(new_argv2,(new_argc2 + nmatches) * sizeof(char *));
- err = MemError(); if (err) goto error;
- for (j = 0; j<nmatches; ++j) {
- if (pathname == 0L)
- (*new_argv2)[new_argc2 + j] = (*matches)[j];
- else {
- int match_len = strlen((*matches)[j]);
- int pathname_len = strlen(pathname);
- char *complete_match = NewPtr(match_len + pathname_len + 2);
- strcpy(complete_match,pathname);
- if (lastchar(pathname) != '/') strcat(complete_match,"/");
- strcat(complete_match,(*matches)[j]);
- (*new_argv2)[new_argc2 + j] = complete_match;
- }
- }
- new_argc2 += nmatches;
-
- DisposHandle(matches);
-
- dispose_file_list(file_list,nfiles);
- }
- else {
- SetHandleSize(new_argv2,(new_argc2 + 1) * sizeof(char *));
- err = MemError(); if (err) goto error;
- (*new_argv2)[new_argc2] = (*new_argv1)[i];
- ++new_argc2;
- }
-
- if (pathname != 0L) DisposPtr(pathname);
- }
-
- if (debug) {
- printf("After expansion, there are %d arguments:\n",new_argc2);
- for (i = 0; i<new_argc2; ++i)
- printf(">%s<\n",(*new_argv2)[i]);
- }
-
- // Add final null pointer to argument list
- SetHandleSize(new_argv2,(new_argc2 + 1) * sizeof(char *));
- err = MemError(); if (err) goto error;
- (*new_argv2)[new_argc2] = 0L;
-
- HLock(new_argv2);
- newprogname = (*new_argv2)[0];
- if (!strcmp(newprogname,"pwd")) {
- if (cwd_err)
- printf("No current directory is set.\n");
- else
- printf("%s\n",cwd);
- }
- else if (!strcmp(newprogname,"cd")) {
- if (new_argc2 == 1)
- chdir("~/");
- else if ((*new_argv2)[1][0] == '/' ||
- ((*new_argv2)[1][0] == '~' && (*new_argv2)[1][1] != '\0'))
- chdir((*new_argv2)[1]);
- else {
- Handle s;
- FSSpec spec;
- char *p;
-
- // We need to check that the result is indeed a directory.
-
- if (cwd_err) { err = memFullErr; goto error; }
- p = NewPtr(strlen(cwd) + strlen((*new_argv2)[1]) + 2);
- err = MemError(); if (err) goto error;
- strcpy(p,cwd);
- if (p[strlen(p)-1] != '/') strcat(p,"/");
- strcat(p,(*new_argv2)[1]);
- err = chdir(p);
- DisposPtr(p);
- }
-
- cwd_err = (getwd(cwd) == 0L);
- if (cwd_err) fprintf(stderr,"Couldn't change directory\n");
- }
- else if (!strcmp(newprogname,"exit"))
- exit(0);
- else if (!strcmp(newprogname,"debug"))
- debug = !debug;
- else {
- if (newprogname[0] != '/') {
- // Our kludge for an absence of a PATH environment variable
- char *p = NewPtr(strlen(newprogname) + 6);
- strcpy(p,"/bin/");
- strcat(p,newprogname);
- (*new_argv2)[0] = p;
- }
-
- // Must flush. What about stdin? The buffer contents just get lost.
- fflush(stdout);
- fflush(stderr);
-
- pid = vfork();
-
- if (pid == -1) {
- fprintf(stderr,"%s: Can't start process '%s'\n",progname,newprogname);
- return;
- }
-
- if (pid == 0) {
- execvp((*new_argv2)[0],*new_argv2);
- fprintf(stderr,"%s: Can't start process '%s'\n",progname,newprogname);
- _exit(1);
- }
-
- if (debug) DebugStr68k("\p%%% Returned from vfork, calling wait");
- wait(&status);
- if (debug) DebugStr68k("\p%%% Returned from wait");
- }
-
- error:
- if (err == noneFoundErr) fprintf(stderr,"%s: None found\n",progname);
- if (err == memFullErr) fprintf(stderr,"%s: Out of memory\n",progname);
- if (err == dirNFErr) fprintf(stderr,"%s: Directory not found\n",progname);
- if (err == fnfErr) fprintf(stderr,"%s: File not found\n",progname);
- if (new_argv1) DisposHandle(new_argv1);
- if (new_argv2) DisposHandle(new_argv2);
- }
-
- int
- main(int argc,char **argv)
- {
- int k,len,c;
- char *p,s[256];
- char interactive,command_in_line;
- // char *argv1[4];
-
- progname = argv[0];
-
- #if 0
- argv1[0] = "sh";
- argv1[1] = "-c";
- argv1[2] = "ls /Rockhopper";
- argv1[2] = "pwd";
- argv1[3] = 0L;
-
- argc = 3;
- argv = argv1;
- init_unix_io_driver(1);
- #endif
-
- interactive = command_in_line = 0;
-
- while (1) {
- c = getopt(argc,argv,"ci");
- if (c == EOF) break;
- switch (c) {
- case 'c': command_in_line = 1; break;
- case 'i': interactive = 1; break;
- }
- }
-
- k = optind;
-
- if (command_in_line) {
- do_one_command(argv[k]);
- return 0;
- }
- else {
- while (1) {
- printf("$ ");
- fflush(stdout);
- p = fgets(s,sizeof s,stdin);
- if (p == 0L || feof(stdin)) {
- printf("^D\n");
- fflush(stdout);
- return 0;
- }
- len = strlen(s);
- if (len>=1) s[len-1] = '\0';
- if (s[0] != '\0') {
- if (debug) printf("Got command: >%s<\n",s);
- do_one_command(s);
- }
- }
- return 0;
- }
- }
-
- static int
- has_star(char *s)
- {
- while (1) {
- if (*s == '\0') return 0;
- if (*s == '*') return 1;
- ++s;
- }
- }
-